/*
 * Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.dlc.shop.discount.api.manager.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import com.dlc.shop.bean.app.dto.*;
import com.dlc.shop.bean.enums.OrderActivityType;
import com.dlc.shop.bean.model.OfflineHandleEventItem;
import com.dlc.shop.bean.vo.ShopCartWithAmountVO;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.discount.api.dto.DiscountSumDto;
import com.dlc.shop.discount.api.service.DiscountManagerService;
import com.dlc.shop.manager.DiscountShopCartManager;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 默认的购物车链进行组装时的操作
 *
 * @author FrozenWatermelon
 */
@Component
@AllArgsConstructor
public class DiscountShopCartManagerImpl implements DiscountShopCartManager {

    private final DiscountManagerService discountManagerService;

    /**
     * 计算满减，并组合购物车 + 购物车金额
     *
     * @param shopCartWithAmount 购物车列表和金额信息
     */
    @Override
    public void calculateDiscountAndMakeUpShopCartAndAmount(ShopCartWithAmountVO shopCartWithAmount) {
        List<ShopCartDto> shopCarts = shopCartWithAmount.getShopCarts();
        shopCarts = calculateDiscountAndMakeUpShopCart(shopCarts);
        shopCartWithAmount.setShopCarts(shopCarts);
    }

    /**
     * 计算满减，并重新组合购物车
     * @param shopCarts 购物项
     * @return void
     */
    @Override
    public List<ShopCartDto> calculateDiscountAndMakeUpShopCart(List<ShopCartDto> shopCarts) {
        List<ShopCartDto> newShopCart = new ArrayList<>();
        for (ShopCartDto shopCart : shopCarts) {
            List<ShopCartItemDto> canDiscountShopCartItems = shopCart.getShopCartItemDiscounts()
                    .get(0).getShopCartItems().stream().filter(shopCartItemDto ->
                        // 套餐不参与满减
                        (Objects.isNull(shopCartItemDto.getComboId()) || shopCartItemDto.getComboId() == 0)
//                        // 预售不参与满减
//                        && (Objects.isNull(shopCartItemDto.getPreSellStatus()) || Objects.equals(shopCartItemDto.getPreSellStatus(), 0))
                    )
                    .collect(Collectors.toList());
            if (CollUtil.isEmpty(canDiscountShopCartItems)) {
                // 不参与满减活动
                newShopCart.add(shopCart);
            } else {
                // 计算店铺的满减金额
                newShopCart.add(reBuildShopCart(shopCart, canDiscountShopCartItems));
            }
        }
        return newShopCart;
    }

    /**
     * 重新组装购物车
     */
    private ShopCartDto reBuildShopCart(ShopCartDto shopCart, List<ShopCartItemDto> shopCartItems) {
        // 购物车项顺序
        List<Long> cartOrderArr = shopCartItems.stream().map(ShopCartItemDto::getBasketId).toList();
        // 订单项金额从小到大排序
        shopCartItems = shopCartItems.stream().sorted(Comparator.comparingDouble(ShopCartItemDto::getActualTotal)).collect(Collectors.toList());

        shopCart.setShopReduce(0.0);
        shopCart.setDiscountReduce(0.0);
        // 初步计算店铺中每个满减的优惠金额，并选择优惠最大的满减活动（自动选择触发条件：立即提交订单或者购物车不指定满减活动）
        DiscountSumDto discountSum = discountManagerService.calculateDiscount(shopCart.getShopId(), shopCartItems);
        List<ShopCartItemDiscountDto> shopCartItemDiscountList = Lists.newArrayList();
        // 对数据进行组装
        shopCartItems.forEach(shopCartItemDto -> shopCartItemDto.setDiscountId(null == shopCartItemDto.getDiscountId() ? 0L : shopCartItemDto.getDiscountId()));
        // 通过活动项id划分,获取有活动的商品项
        Map<Long, List<ShopCartItemDto>> hasDiscountShopCartItemMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDto::getDiscountId));

        double reduce = 0.0;
        double total = 0.0;
        int totalCount = 0;
       // double supplierPriceTotal = 0;
        for (Long discountId : hasDiscountShopCartItemMap.keySet()) {
            // 获取该列表
            List<ShopCartItemDto> shopCartItemList = hasDiscountShopCartItemMap.get(discountId);
            ChooseDiscountItemDto chooseDiscountItemDto = discountManagerService.getChooseDiscountItemDto(discountSum, discountId);
            double discountAmount = 0.0;
            ShopCartItemDiscountDto shopCartItemDiscount = new ShopCartItemDiscountDto();

            // 计算分摊优惠金额
            for (int index = 0; index < shopCartItemList.size(); index++) {
                ShopCartItemDto shopCartItem = shopCartItemList.get(index);
                total = Arith.add(total, shopCartItem.getProductTotalAmount());
               // supplierPriceTotal = Arith.add(supplierPriceTotal, shopCartItem.getSupplierPrice());
                totalCount += shopCartItem.getProdCount();
                // 加上赠品的数量
                if(CollectionUtil.isNotEmpty(shopCartItem.getGiveawayShopCartItemList())){
                    totalCount += shopCartItem.getGiveawayShopCartItemList().stream().mapToInt(ProductItemDto::getProdCount).sum();
                }
                // !BooleanUtil.isTrue(shopCartItem.getIsChecked()) && Objects.nonNull(shopCartItem.getIsChecked())
                // 上面为原判断，isChecked != true,又不等于null，也就是说isChecked只能为false
                if (Objects.equals(shopCartItem.getIsChecked(), 0)) {
                    continue;
                }
                double shareReduce = 0.0;
                // 满减活动过期、删除等原因没有查询到时， 不需要计算满减的金额，直接下一个循环即可
                if (Objects.isNull(chooseDiscountItemDto)) {
                    shopCartItem.setShareReduce(shareReduce);
                    continue;
                }
                shareReduce = this.getShareReduce(shopCartItems, chooseDiscountItemDto, discountAmount, shopCartItemDiscount, index, shopCartItem);
                discountAmount = Arith.add(discountAmount, shareReduce);
            }
            discountAmount = this.recalculateDiscountAmount(shopCartItemList, chooseDiscountItemDto, discountAmount);

            // 满减活动项信息中的优惠金额，更改为计算后实际的优惠金额， 一般情况下都是等于原本优惠金额
            // 极端情况为多个0.01的商品达到了满减的条件，但由于商品金额已经为最小值，无法再扣除优惠，而出现的实际满减金额小于活动设置的满减金额
            if (Objects.nonNull(chooseDiscountItemDto)) {
                chooseDiscountItemDto.setReduceAmount(discountAmount);
            }
            // 计算总的优惠金额，一定要等满减金额计算完成不再变动后再进行总优惠金额的计算
            if (discountAmount > 0) {
                reduce = Arith.add(reduce, Arith.roundByBanker(discountAmount,2));
            }
            // 把购物车项的商品顺序还原
            shopCartItemList.sort(Comparator.comparingInt(prev -> cartOrderArr.indexOf(prev.getBasketId())));
            shopCartItemDiscount.setShopCartItems(shopCartItemList);
            shopCartItemDiscount.setMaxBasketId(shopCartItemList.stream().max(Comparator.comparing(ShopCartItemDto::getBasketId)).get().getBasketId());
            shopCartItemDiscount.setChooseDiscountItemDto(chooseDiscountItemDto);
            shopCartItemDiscountList.add(shopCartItemDiscount);
        }
        // 倒序排序，将拥有优惠活动的商品放到最上面
        Collections.reverse(shopCartItemDiscountList);
        shopCartItemDiscountList.sort(Comparator.comparing(ShopCartItemDiscountDto::getMaxBasketId).reversed());
        // 除满减外其他活动的商品构建
        this.buildOtherShopCartItem(shopCart, shopCartItemDiscountList);

        shopCart.setShopCartItemDiscounts(shopCartItemDiscountList);
        shopCart.setTotal(total);
        shopCart.setTotalCount(totalCount);
        shopCart.setActualTotal(Arith.sub(total, reduce));
        //shopCart.setSupplierPriceTotal(supplierPriceTotal);
        shopCart.setDiscountReduce(reduce);
        // 最开始的店铺满减
        shopCart.setShopReduce(reduce);
        return shopCart;
    }

    private double getShareReduce(List<ShopCartItemDto> shopCartItems, ChooseDiscountItemDto chooseDiscountItemDto, double discountAmount, ShopCartItemDiscountDto shopCartItemDiscount, int index, ShopCartItemDto shopCartItem) {
        double shareReduce;
        if (Objects.isNull(shopCartItemDiscount.getActivityType())) {
            shopCartItemDiscount.setActivityType(OrderActivityType.DISCOUNT.value());
        }
        double reduceAmount = Arith.roundByBanker(chooseDiscountItemDto.getReduceAmount(),2);
        // 是最后一项商品的优惠金额计算 - 将前面计算中剩余的满减金额，都放着最后一项进行扣除
        if (index + 1 == shopCartItems.size()) {
            shareReduce = reduceAmount - discountAmount;
        }
        // 不是列表中最后一项商品的优惠金额计算 - 按公式计算满减金额即可，偏差值留给最后一步再去计算
        else {
            // 分摊金额 = 该优惠活动优惠金额 * (商品金额 / 参与该活动的商品总金额)
            shareReduce = Arith.roundByBanker(Arith.mul(chooseDiscountItemDto.getReduceAmount(), Arith.div(shopCartItem.getProductTotalAmount(),
                    chooseDiscountItemDto.getProdsPrice())),2);
        }
        // 判断下满减优惠金额是否大于等于商品实际金额，由于商品的最小金额为0.01，所以满减优惠金额必须要小于商品实际金额
        if (shareReduce >= shopCartItem.getActualTotal()) {
            shareReduce = Arith.sub(shopCartItem.getActualTotal(), Constant.MIN_PRODUCT_AMOUNT);
        }

        // 第一个优惠就是满减
        shopCartItem.setShareReduce(shareReduce);
        shopCartItem.setDiscountAmount(shareReduce);
        shopCartItem.setActualTotal(Arith.sub(shopCartItem.getActualTotal(), shareReduce));
        return shareReduce;
    }

    private double recalculateDiscountAmount(List<ShopCartItemDto> shopCartItemList, ChooseDiscountItemDto chooseDiscountItemDto, double discountAmount) {
        // 没有满减活动的信息， 或者优惠金额已分摊完成
        if (Objects.isNull(chooseDiscountItemDto) || discountAmount >= chooseDiscountItemDto.getReduceAmount()) {
            return discountAmount;
        }
        // 如果实际计算的满减金额都是小于满减活动原本的优惠金额，再重新分摊下剩余的满减金额
        // 按商品实际金额倒序，从金额最大的开始分摊
        shopCartItemList.sort(Comparator.comparing(ShopCartItemDto::getActualTotal).reversed());
        for (ShopCartItemDto shopCartItem : shopCartItemList) {
            // 未勾选不参与满减， 或者满减金额已分摊完毕
            if (!Objects.equals(shopCartItem.getIsChecked(), 1) || discountAmount >= chooseDiscountItemDto.getReduceAmount()) {
                continue;
            }
            // 商品剩余可分摊金额 = 商品实际金额 - 商品满减优惠金额（上面循环中计算的满减金额） - 商品最小金额（最小金额为0.01）
            double canShareReduce =  Arith.sub(Arith.sub(shopCartItem.getActualTotal(), shopCartItem.getDiscountAmount()), Constant.MIN_PRODUCT_AMOUNT);
            if (canShareReduce <= 0) {
                continue;
            }
            // 满减剩余可分摊金额
            double shareReduce = Arith.sub(chooseDiscountItemDto.getReduceAmount(), discountAmount);
            // 商品剩余可分摊金额 和 满减剩余可分摊金额 取最小值
            shareReduce = Math.min(canShareReduce, shareReduce);
            // 累加优惠金额
            shopCartItem.setShareReduce(Arith.add(shopCartItem.getShareReduce(), shareReduce));
            shopCartItem.setDiscountAmount(shopCartItem.getShareReduce());
            shopCartItem.setActualTotal(Arith.sub(shopCartItem.getActualTotal(), shareReduce));
            discountAmount = Arith.add(discountAmount, shareReduce);
        }
        return discountAmount;
    }

    private void buildOtherShopCartItem(ShopCartDto shopCart, List<ShopCartItemDiscountDto> shopCartItemDiscountVOList) {
        List<ShopCartItemDto> comboShopCartItemList = shopCart.getShopCartItemDiscounts().get(0).getShopCartItems().stream().filter(shopCartItemDto ->
                (Objects.nonNull(shopCartItemDto.getComboId()) && shopCartItemDto.getComboId() != 0)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(comboShopCartItemList)) {
            shopCartItemDiscountVOList.add(new ShopCartItemDiscountDto(comboShopCartItemList));
        }
//        List<ShopCartItemDto> preSellShopCartItemList = shopCart.getShopCartItemDiscounts().get(0).getShopCartItems().stream().filter(shopCartItemDto ->
//                (Objects.nonNull(shopCartItemDto.getPreSellStatus()) && Objects.equals(shopCartItemDto.getPreSellStatus(), 1))).collect(Collectors.toList());
//        if (CollUtil.isNotEmpty(preSellShopCartItemList)) {
//            shopCartItemDiscountVOList.add(new ShopCartItemDiscountDto(preSellShopCartItemList));
//        }
    }
}
